﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
//using static System.Runtime.InteropServices.JavaScript.JSType;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip;
using MvCameraControl;
using System.Threading;

namespace Vision.Modules.ImageLoad
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class ImageLoad : Window
    {

        // 枚举的相机类型
        readonly DeviceTLayerType enumTLayerType = DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvUsbDevice
    | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvGenTLCXPDevice | DeviceTLayerType.MvGenTLCameraLinkDevice | DeviceTLayerType.MvGenTLXoFDevice;

        List<IDeviceInfo> deviceInfoList = new List<IDeviceInfo>();
        IDevice device = null;

        bool isGrabbing = false;        // 是否正在取图 
        Thread receiveThread = null;    //接收图像线程
        bool isRecord = false;          //是否正在录像
        IntPtr pictureBoxHandle = IntPtr.Zero; // 显示图像的控件句柄
        private IFrameOut frameForSave; //获取到的帧信息，用于保存图像
        private readonly object saveImageLock = new object();

        public ImageLoad()
        {
            InitializeComponent();
            Closing += Window_Closing;
            Loaded += new RoutedEventHandler(BasicDemoWindow_Load);
        }

        private void BasicDemoWindow_Load(object sender, RoutedEventArgs e)
        {
            // 初始化 SDK 
            SDKSystem.Initialize();

            //  枚举设备 
            RefreshDeviceList();
        }

        /// <summary>
        /// 显示错误信息
        /// </summary>
        private void ShowErrorMsg(string message, int errorCode)
        {
            string errorMsg;
            if (errorCode == 0)
            {
                errorMsg = message;
            }
            else
            {
                errorMsg = message + ": Error =" + String.Format("{0:X}", errorCode);
            }

            switch (errorCode)
            {
                case MvError.MV_E_HANDLE: errorMsg += " Error or invalid handle "; break;
                case MvError.MV_E_SUPPORT: errorMsg += " Not supported function "; break;
                case MvError.MV_E_BUFOVER: errorMsg += " Cache is full "; break;
                case MvError.MV_E_CALLORDER: errorMsg += " Function calling order error "; break;
                case MvError.MV_E_PARAMETER: errorMsg += " Incorrect parameter "; break;
                case MvError.MV_E_RESOURCE: errorMsg += " Applying resource failed "; break;
                case MvError.MV_E_NODATA: errorMsg += " No data "; break;
                case MvError.MV_E_PRECONDITION: errorMsg += " Precondition error, or running environment changed "; break;
                case MvError.MV_E_VERSION: errorMsg += " Version mismatches "; break;
                case MvError.MV_E_NOENOUGH_BUF: errorMsg += " Insufficient memory "; break;
                case MvError.MV_E_UNKNOW: errorMsg += " Unknown error "; break;
                case MvError.MV_E_GC_GENERIC: errorMsg += " General error "; break;
                case MvError.MV_E_GC_ACCESS: errorMsg += " Node accessing condition error "; break;
                case MvError.MV_E_ACCESS_DENIED: errorMsg += " No permission "; break;
                case MvError.MV_E_BUSY: errorMsg += " Device is busy, or network disconnected "; break;
                case MvError.MV_E_NETER: errorMsg += " Network error "; break;
            }

            MessageBox.Show(errorMsg, "PROMPT");
        }

        private void RefreshDeviceList()
        {
            // 创建设备列表 
            cbDeviceList.Items.Clear();
            int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out deviceInfoList);
            if (nRet != MvError.MV_OK)
            {
                ShowErrorMsg("Enumerate devices fail!", nRet);
                return;
            }

            // 在窗体列表中显示设备名
            for (int i = 0; i < deviceInfoList.Count; i++)
            {
                IDeviceInfo deviceInfo = deviceInfoList[i];
                if (deviceInfo.UserDefinedName != "")
                {
                    cbDeviceList.Items.Add(deviceInfo.TLayerType.ToString() + ": " + deviceInfo.UserDefinedName + " (" + deviceInfo.SerialNumber + ")");
                }
                else
                {
                    cbDeviceList.Items.Add(deviceInfo.TLayerType.ToString() + ": " + deviceInfo.ManufacturerName + " " + deviceInfo.ModelName + " (" + deviceInfo.SerialNumber + ")");
                }
            }

            // 选择第一项 
            if (deviceInfoList.Count != 0)
            {
                cbDeviceList.SelectedIndex = 0;
            }
        }
        private void bnEnum_Click(object sender, RoutedEventArgs e)
        {
            RefreshDeviceList();
        }

        private void bnOpen_Click(object sender, RoutedEventArgs e)
        {
            if (deviceInfoList.Count == 0 || cbDeviceList.SelectedIndex == -1)
            {
                ShowErrorMsg("No device, please select", 0);
                return;
            }

            // 获取选择的设备信息 
            IDeviceInfo deviceInfo = deviceInfoList[cbDeviceList.SelectedIndex];

            try
            {
                // 打开设备 
                device = DeviceFactory.CreateDevice(deviceInfo);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Create Device fail!" + ex.Message);
                return;
            }

            int result = device.Open();
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Open Device fail!", result);
                return;
            }

            //判断是否为gige设备 
            if (device is IGigEDevice)
            {
                //转换为gigE设备
                IGigEDevice gigEDevice = device as IGigEDevice;

                // 探测网络最佳包大小(只对GigE相机有效)
                int optionPacketSize;
                result = gigEDevice.GetOptimalPacketSize(out optionPacketSize);
                if (result != MvError.MV_OK)
                {
                    ShowErrorMsg("Warning: Get Packet Size failed!", result);
                }
                else
                {
                    result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
                    if (result != MvError.MV_OK)
                    {
                        ShowErrorMsg("Warning: Set Packet Size failed!", result);
                    }
                }
            }

            // 设置采集连续模式 
            device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
            device.Parameters.SetEnumValueByString("TriggerMode", "Off");

            //控件操作 
            SetCtrlWhenOpen();

            // 获取参数 
            bnGetParam_Click(null, null);
        }

        /// 控件操作 
        private void SetCtrlWhenOpen()
        {
            bnOpen.IsEnabled = false;
            bnClose.IsEnabled = true;

            bnStartGrab.IsEnabled = true;
            bnStopGrab.IsEnabled = false;
            bnContinuesMode.IsEnabled = true;
            bnContinuesMode.IsChecked = true;
            bnTriggerMode.IsEnabled = true;
            cbSoftTrigger.IsEnabled = false;
            bnTriggerExec.IsEnabled = false;

            tbExposure.IsEnabled = true;
            tbGain.IsEnabled = true;
            tbFrameRate.IsEnabled = true;
            bnGetParam.IsEnabled = true;
            bnSetParam.IsEnabled = true;
        }

        private void bnClose_Click(object sender, RoutedEventArgs e)
        {
            // 取流标志位清零 
            if (isGrabbing == true)
            {
                bnStopGrab_Click(sender, e);
            }

            // 关闭设备
            if (device != null)
            {
                device.Close();
                device.Dispose();
            }

            // 控件操作
            SetCtrlWhenClose();
        }

        private void SetCtrlWhenClose()
        {
            bnOpen.IsEnabled = true;

            bnClose.IsEnabled = false;
            bnStartGrab.IsEnabled = false;
            bnStopGrab.IsEnabled = false;
            bnContinuesMode.IsEnabled = false;
            bnTriggerMode.IsEnabled = false;
            cbSoftTrigger.IsEnabled = false;
            bnTriggerExec.IsEnabled = false;

            tbExposure.IsEnabled = false;
            tbGain.IsEnabled = false;
            tbFrameRate.IsEnabled = false;
            bnGetParam.IsEnabled = false;
            bnSetParam.IsEnabled = false;

            bnSaveBmp.IsEnabled = false;
            bnSaveJpg.IsEnabled = false;
            bnSaveTiff.IsEnabled = false;
            bnSavePng.IsEnabled = false;
        }

        private void bnContinuesMode_Checked(object sender, RoutedEventArgs e)
        {
            device.Parameters.SetEnumValueByString("TriggerMode", "Off");
            cbSoftTrigger.IsEnabled = false;
            bnTriggerExec.IsEnabled = false;
        }

        private void bnTriggerMode_Checked(object sender, RoutedEventArgs e)
        {
            // 打开触发模式 
            device.Parameters.SetEnumValueByString("TriggerMode", "On");

            // 触发源选择:0 - Line0; 
            //           1 - Line1;
            //           2 - Line2;
            //           3 - Line3;
            //           4 - Counter;
            //           7 - Software;
            if ((bool)cbSoftTrigger.IsChecked)
            {
                device.Parameters.SetEnumValueByString("TriggerSource", "Software");
                if (isGrabbing)
                {
                    bnTriggerExec.IsEnabled = true;
                }
            }
            else
            {
                device.Parameters.SetEnumValueByString("TriggerSource", "Line0");
            }
            cbSoftTrigger.IsEnabled = true;
            cbSoftTrigger.IsChecked = true;
        }

        public void ReceiveThreadProcess()
        {
            IFrameOut frameOut = null;
            int result = MvError.MV_OK;

            while (isGrabbing)
            {
                result = device.StreamGrabber.GetImageBuffer(1000, out frameOut);
                if (result == MvError.MV_OK)
                {
                    if(isRecord)
                    {
                        device.VideoRecorder.InputOneFrame(frameOut.Image);
                    }

                    lock (saveImageLock)
                    {
                        frameForSave = frameOut.Clone() as IFrameOut;
                    }

                    device.ImageRender.DisplayOneFrame(pictureBoxHandle, frameOut.Image);

                    device.StreamGrabber.FreeImageBuffer(frameOut);
                }
/*                lock (saveImageLock)
                {
                    frameForSave = frameOut.Clone() as IFrameOut;
                }*/
            }
        }

        private int SaveImage(ImageFormatInfo imageFormatInfo)
        {
            if (frameForSave == null)
            {
                throw new Exception("No valid image");
            }

            string imagePath = "Image_w" + frameForSave.Image.Width.ToString() + "_h" + frameForSave.Image.Height.ToString() + "_fn" + frameForSave.FrameNum.ToString() + "." + imageFormatInfo.FormatType.ToString();

            lock (saveImageLock)
            {
                return device.ImageSaver.SaveImageToFile(imagePath, frameForSave.Image, imageFormatInfo, CFAMethod.Equilibrated);
            }
        }

        private void bnSaveBmp_Click(object sender, EventArgs e)
        {
            int result;

            try
            {
                ImageFormatInfo imageFormatInfo = new ImageFormatInfo();
                imageFormatInfo.FormatType = ImageFormatType.Bmp;

                result = SaveImage(imageFormatInfo);
                if (result != MvError.MV_OK)
                {
                    ShowErrorMsg("Save Image Fail!", result);
                    return;
                }
                else
                {
                    ShowErrorMsg("Save Image Succeed!", 0);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Save Image Failed, " + ex.Message);
                return;
            }


        }

        private void bnSaveJpg_Click(object sender, EventArgs e)
        {
            int result;

            try
            {
                ImageFormatInfo imageFormatInfo;
                imageFormatInfo.FormatType = ImageFormatType.Jpeg;
                imageFormatInfo.JpegQuality = 80;

                result = SaveImage(imageFormatInfo);
                if (result != MvError.MV_OK)
                {
                    ShowErrorMsg("Save Image Fail!", result);
                    return;
                }
                else
                {
                    ShowErrorMsg("Save Image Succeed!", 0);
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show("Save Image Failed, " + ex.Message);
                return;
            }
        }

        private void bnSavePng_Click(object sender, EventArgs e)
        {
            int result;

            try
            {
                ImageFormatInfo imageFormatInfo = new ImageFormatInfo();
                imageFormatInfo.FormatType = ImageFormatType.Png;

                result = SaveImage(imageFormatInfo);
                if (result != MvError.MV_OK)
                {
                    ShowErrorMsg("Save Image Fail!", result);
                    return;
                }
                else
                {
                    ShowErrorMsg("Save Image Succeed!", 0);
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show("Save Image Failed, " + ex.Message);
                return;
            }
        }

        private void bnSaveTiff_Click(object sender, EventArgs e)
        {
            int result;
            try
            {
                ImageFormatInfo imageFormatInfo = new ImageFormatInfo();
                imageFormatInfo.FormatType = ImageFormatType.Tiff;

                result = SaveImage(imageFormatInfo);
                if (result != MvError.MV_OK)
                {
                    ShowErrorMsg("Save Image Fail!", result);
                    return;
                }
                else
                {
                    ShowErrorMsg("Save Image Succeed!", 0);
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show("Save Image Failed, " + ex.Message);
                return;
            }
        }
        private void bnStartGrab_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // 标志位置位true 
                isGrabbing = true;
                pictureBoxHandle = displayArea.Handle;

                receiveThread = new Thread(ReceiveThreadProcess);
                receiveThread.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Start thread failed!, " + ex.Message);
                return;
            }

            // 开始采集
            int result = device.StreamGrabber.StartGrabbing();
            if (result != MvError.MV_OK)
            {
                isGrabbing = false;
                receiveThread.Join();
                ShowErrorMsg("Start Grabbing Fail!", result);
                return;
            }

            // 控件操作
            SetCtrlWhenStartGrab();
        }

        private void SetCtrlWhenStartGrab()
        {
            bnStartGrab.IsEnabled = false;
            bnStopGrab.IsEnabled = true;

            bnSaveBmp.IsEnabled = true;
            bnSaveJpg.IsEnabled = true;
            bnSaveTiff.IsEnabled = true;
            bnSavePng.IsEnabled = true;
            bnStartRecord.IsEnabled = true;
            bnStopRecord.IsEnabled = false;

            if ((bool)bnTriggerMode.IsChecked)
            {
                cbSoftTrigger.IsEnabled = true;
                if ((bool)cbSoftTrigger.IsChecked)
                {
                    bnTriggerExec.IsEnabled = true;
                }
            }
        }

        private void bnStopGrab_Click(object sender, RoutedEventArgs e)
        {
            if (isRecord)
            {
                bnStopRecord_Click(sender, e);
            }
            // 标志位设为false
            isGrabbing = false;
            receiveThread.Join();

            // 停止采集 
            int result = device.StreamGrabber.StopGrabbing();
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Stop Grabbing Fail!", result);
            }


            // 控件操作
            SetCtrlWhenStopGrab();
        }

        private void bnStartRecord_Click(object sender, EventArgs e)
        {
            if (false == isGrabbing)
            {
                ShowErrorMsg("Not Start Grabbing", 0);
                return;
            }

            IIntValue intValue;
            IEnumValue enumValue;

            uint width;
            uint height;
            MvGvspPixelType pixelType;

            int result;

            result = device.Parameters.GetIntValue("Width", out intValue);
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Get Width failed!", result);
                return;
            }
            width = (uint)intValue.CurValue;

            result = device.Parameters.GetIntValue("Height", out intValue);
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Get Height failed!", result);
                return;
            }
            height = (uint)intValue.CurValue;

            result = device.Parameters.GetEnumValue("PixelFormat", out enumValue);
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Get PixelFormat failed!", result);
                return;
            }
            pixelType = (MvGvspPixelType)enumValue.CurEnumEntry.Value;

            // ch:开始录像 | en:Start record
            RecordParam recordParam;
            recordParam.Width = width;
            recordParam.Height = height;
            recordParam.PixelType = pixelType;
            recordParam.FrameRate = float.Parse(tbFrameRate.Text);
            recordParam.BitRate = 1000;
            recordParam.FormatType = VideoFormatType.AVI;

            result = device.VideoRecorder.StartRecord("./Record.avi", recordParam);
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Start Record Fail!", result);
                return;
            }

            isRecord = true;

            SetCtrlWhenStartRecord();
        }

        private void bnStopRecord_Click(object sender, RoutedEventArgs e)
        {
            if (false == isGrabbing)
            {
                ShowErrorMsg("Not Start Grabbing", 0);
                return;
            }
            int result = device.VideoRecorder.StopRecord();
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Stop Record Fail!",result);
            }
            isRecord = false;
            SetCtrlWhenStopRecord();
        }

        private void SetCtrlWhenStartRecord()
        {
            bnStartRecord.IsEnabled = false;
            bnStopRecord.IsEnabled = true;
        }

        private void SetCtrlWhenStopRecord()
        {
            bnStartRecord.IsEnabled = true;
            bnStopRecord.IsEnabled = false;
        }
        // 控件操作 
        private void SetCtrlWhenStopGrab()
        {
            bnStartGrab.IsEnabled = true;
            bnStopGrab.IsEnabled = false;

            cbSoftTrigger.IsEnabled = false;
            bnTriggerExec.IsEnabled = false;

            bnSaveBmp.IsEnabled = false;
            bnSaveJpg.IsEnabled = false;
            bnSaveTiff.IsEnabled = false;
            bnSavePng.IsEnabled = false;
            bnStartRecord.IsEnabled = false;
            bnStopRecord.IsEnabled = false;
        }

        private void bnTriggerExec_Click(object sender, RoutedEventArgs e)
        {
            // 触发命令
            int result = device.Parameters.SetCommandValue("TriggerSoftware");
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Trigger Software Fail!", result);
            }
        }

        private void cbSoftTrigger_Checked(object sender, RoutedEventArgs e)
        {
            // 触发源设为软触发 
            device.Parameters.SetEnumValueByString("TriggerSource", "Software");
            if (isGrabbing)
            {
                bnTriggerExec.IsEnabled = true;
            }
        }

        private void cbSoftTrigger_Unchecked(object sender, RoutedEventArgs e)
        {
            device.Parameters.SetEnumValueByString("TriggerSource", "Line0");
            bnTriggerExec.IsEnabled = false;
        }

        /// <summary>
        /// 获取触发模式
        /// </summary>
        private void GetTriggerMode()
        {
            IEnumValue enumValue;
            int result = device.Parameters.GetEnumValue("TriggerMode", out enumValue);
            if (result == MvError.MV_OK)
            {
                if (enumValue.CurEnumEntry.Symbolic == "On")
                {
                    bnTriggerMode.IsChecked = true;
                    bnContinuesMode.IsChecked = false;

                    result = device.Parameters.GetEnumValue("TriggerSource", out enumValue);
                    if (result == MvError.MV_OK)
                    {
                        if (enumValue.CurEnumEntry.Symbolic == "TriggerSoftware")
                        {
                            cbSoftTrigger.IsEnabled = true;
                            cbSoftTrigger.IsChecked = true;
                            if (isGrabbing)
                            {
                                bnTriggerExec.IsEnabled = true;
                            }
                        }
                    }
                }
                else
                {
                    bnContinuesMode.IsChecked = true;
                    bnTriggerMode.IsChecked = false;
                }
            }
        }

        private void bnGetParam_Click(object sender, RoutedEventArgs e)
        {
            GetTriggerMode();

            IFloatValue floatValue;
            int result = device.Parameters.GetFloatValue("ExposureTime", out floatValue);
            if (result == MvError.MV_OK)
            {
                tbExposure.Text = floatValue.CurValue.ToString("F1");
            }

            result = device.Parameters.GetFloatValue("Gain", out floatValue);
            if (result == MvError.MV_OK)
            {
                tbGain.Text = floatValue.CurValue.ToString("F1");
            }

            result = device.Parameters.GetFloatValue("ResultingFrameRate", out floatValue);
            if (result == MvError.MV_OK)
            {
                tbFrameRate.Text = floatValue.CurValue.ToString("F1");
            }

            IEnumValue enumValue;
            result = device.Parameters.GetEnumValue("PixelFormat", out enumValue);
            if (result == MvError.MV_OK)
            {
                tbPixelFormat.Text = enumValue.CurEnumEntry.Symbolic;
            }
        }

        private void bnSetParam_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                float.Parse(tbExposure.Text);
                float.Parse(tbGain.Text);
                float.Parse(tbFrameRate.Text);
            }
            catch
            {
                ShowErrorMsg("Please enter correct type!", 0);
                return;
            }

            device.Parameters.SetEnumValue("ExposureAuto", 0);
            int result = device.Parameters.SetFloatValue("ExposureTime", float.Parse(tbExposure.Text));
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Set Exposure Time Fail!", result);
            }

            device.Parameters.SetEnumValue("GainAuto", 0);
            result = device.Parameters.SetFloatValue("Gain", float.Parse(tbGain.Text));
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Set Gain Fail!", result);
            }

            result = device.Parameters.SetFloatValue("AcquisitionFrameRate", float.Parse(tbFrameRate.Text));
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Set Frame Rate Fail!", result);
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            bnClose_Click(null, null);

            // 反初始化SDK 
            SDKSystem.Finalize();
        }
    }
}

